package br.com.poolme.connection;

import java.io.IOException;
import java.util.Hashtable;
import java.util.Vector;

import javax.bluetooth.BluetoothStateException;
import javax.bluetooth.DataElement;
import javax.bluetooth.DeviceClass;
import javax.bluetooth.DiscoveryAgent;
import javax.bluetooth.DiscoveryListener;
import javax.bluetooth.LocalDevice;
import javax.bluetooth.RemoteDevice;
import javax.bluetooth.ServiceRecord;
import javax.bluetooth.UUID;

import javax.microedition.io.Connector;
import javax.microedition.io.StreamConnection;

public class BluetoothConnectionCliente extends BluetoothConnection implements
        DiscoveryListener {

    private Hashtable serverAddress;
    private Vector opponentNames;
    private int actualTransID = 0;
    private boolean searchCanceled;
    private int actualDevice;
    private RemoteDevice[] devicesDiscovered;

    public BluetoothConnectionCliente() {
    }

    public Vector search() throws BluetoothStateException,
            SearchCanceledException {
        opponentNames = new Vector();
        serverAddress = new Hashtable();

        localDevice = LocalDevice.getLocalDevice();
        DiscoveryAgent discoveryAgent = localDevice.getDiscoveryAgent();
        discoveryAgent.startInquiry(DiscoveryAgent.GIAC, this);

        synchronized (this) {
            try {
                this.wait();
            } catch (InterruptedException ignored) {
            }
        }
        if (searchCanceled) {
            throw new SearchCanceledException();
        }
        return opponentNames;
    }

    public void deviceDiscovered(RemoteDevice btDevice, DeviceClass cod) {
    }

    public void servicesDiscovered(int transID, ServiceRecord[] servRecord) {
        for (int i = 0; i < servRecord.length; i++) {
            DataElement data = servRecord[i].getAttributeValue(PLAYER_NAME_KEY);
            opponentNames.addElement(data.getValue());
            //Record the server address.
            serverAddress.put(data.getValue(), servRecord[i].getConnectionURL(
                    0, false));
        }
    }

    public void serviceSearchCompleted(int transID, int respCode) {
        if (++actualDevice >= devicesDiscovered.length) {
            synchronized (this) {
                this.notify();
            }
        } else if (respCode == SERVICE_SEARCH_TERMINATED) {
            searchCanceled = true;
            synchronized (this) {
                this.notify();
            }
        } else {
            searchServiceOnDevice(actualDevice);
        }
    }

    public void inquiryCompleted(int discType) {
        if (discType == INQUIRY_COMPLETED) {
            DiscoveryAgent discoveryAgent = localDevice.getDiscoveryAgent();
            devicesDiscovered = discoveryAgent
                    .retrieveDevices(DiscoveryAgent.CACHED);
            if (devicesDiscovered != null) {
                actualDevice = 0;
                searchServiceOnDevice(actualDevice);
            } else {
                synchronized (this) {
                    this.notify();
                }
            }

        } else if (discType == INQUIRY_TERMINATED) {
            searchCanceled = true;
            synchronized (this) {
                this.notify();
            }
        }
    }

    private void searchServiceOnDevice(int device) {
        DiscoveryAgent discoveryAgent = localDevice.getDiscoveryAgent();
        try {
            actualTransID = discoveryAgent
                    .searchServices(new int[] { PLAYER_NAME_KEY },
                            new UUID[] { RFCOMM_UUID },
                            devicesDiscovered[device], this);
        } catch (BluetoothStateException e) {
            e.printStackTrace();
            synchronized (this) {
                this.notify();
            }
        }
    }

    public void run() {
        try {
            conn = (StreamConnection) Connector.open((String) serverAddress
                    .get(playerName));
            fireConnectionEstablishedEvent();
        } catch (IOException e) {
            fireConnectionErrorEvent(e);
        }
    }

    public void stop() {
        if (conn == null) {
            DiscoveryAgent discoveryAgent = localDevice.getDiscoveryAgent();
            discoveryAgent.cancelInquiry(this);
            discoveryAgent.cancelServiceSearch(actualTransID);
        } else {
            try {
                conn.close();
            } catch (IOException ignored) {
            }
        }
    }
}